package com.jd.jstable.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by chenyipu on 2018/1/10.
 */
public class ReflectionUtil {
    /**
     * 判断参数1的类是不是参数2的子类
     * @param clazz
     * @param superClazz
     * @return
     */
    public static boolean isClass(Class<?> clazz,Class<?> superClazz){
                while (clazz.getSuperclass()!=(null)&&!clazz.getSuperclass().equals(superClazz)&&!clazz.getSuperclass().equals(Object.class)){
                    clazz = clazz.getSuperclass();
                }
                if(clazz.getSuperclass()!=(null)&&clazz.getSuperclass().equals(superClazz)){
                    return true;
        }
        return false;
    }
    /**
     * 判断参数1的类是不是参数2的实现类
     * @param clazz
     * @param superInterface
     * @return
     */
    public static boolean hasImplemented(Class<?> clazz,Class<?> superInterface){
        Stack<Class> stack = new Stack<>();
        Arrays.stream(clazz.getInterfaces()).forEach(interfaxe -> stack.push(interfaxe));
        while(!stack.empty()){
            Class cl = stack.pop();
            if(cl.equals(superInterface)){
                return true;
            }
            //
            Arrays.stream(cl.getInterfaces()).forEach(e -> stack.push(e));
        }
        return false;
    }
    /**
     * 获取当前类与其所有父类中声明的同名的第一个函数
     * @param clazz
     * @param methodName
     * @return
     */
    public static Method findMethodByName(Class clazz, String methodName){
        List<Class> parentClasses = getParentClasses(clazz);
        for (Class e : parentClasses) {
            Optional<Method> optional = Arrays.stream(e.getDeclaredMethods()).filter(ee -> ee.getName().equals(methodName)).findFirst();
            if (optional.isPresent()) {
                return optional.get();
            }
        }
        return null;
    }

    /**
     * 获取当前类与其所有父类中声明的同名的第一个函数
     * @param clazz
     * @param methodName
     * @return
     */
    public static Method findMethod(Class clazz, String methodName, List<Class> parameterClasses) throws NoSuchMethodException {
        List<Class> parentClasses = getParentClasses(clazz);
        for (Class e : parentClasses) {
            Method method = e.getMethod(methodName, parameterClasses.toArray(new Class[parameterClasses.size()]));
            return method;
        }
        return null;
    }

    /**
     * 获取一个类的所有父类
     * 举例:
     * 入参: FileInputStream.class
     * 出参: [class java.io.FileInputStream, class java.io.InputStream]
     * @param clazz
     * @return
     */
    public static List<Class> getParentClasses(Class clazz){
        List<Class> list =new ArrayList<Class>();
        list.add(clazz);
        while (clazz.getSuperclass()!=(null)&&!clazz.getSuperclass().equals(Object.class)){
            clazz = clazz.getSuperclass();
            list.add(clazz);
        }
        return list;
    }

    /**
     * 根据方法名字符串反射调用函数
     * @param object
     * @param method
     * @param parameterClasses
     * @param parameters
     * @return
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static Object invoke(Object object, String method, List<Class> parameterClasses, List<Object> parameters)
            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class clazz = object.getClass();
        Method method1 = findMethod(clazz, method, parameterClasses);
        return method1.invoke(object, parameters.toArray());
    }
    /**
     * 判断参数1的类是不是参数2的子类
     * @param clazz
     * @param superClazz
     * @return
     */
    public static boolean hasExtends(Class clazz, Class superClazz) {
        if(Objects.equals(clazz, superClazz)){
            return true;
        }
        while (clazz.getSuperclass()!=(null)&&!clazz.getSuperclass().equals(Object.class)){
            clazz = clazz.getSuperclass();
            if(Objects.equals(clazz, superClazz)){
                return true;
            }
        }
        return false;
    }
}
